import fg from "fast-glob";
import fs from "fs-extra";
import path from "path";
import { toolchain } from "../toolchain.js";
import moment from "moment";
import sharp from "sharp";
import { getDominantColors } from "color-supreme";
import { RGBColor } from "color-supreme/dist/lib/dominantColors/types.js";
import { UnityHelper } from "./UnityHelper.js";
import { SVN } from "./SVN.js";

declare interface IResolution {
    file: string,
    guid: string,
    color: RGBColor | null
}

export class ImageReplacer {    

    public async test(): Promise<void> {
        // run dp_cn:replaceImage
        const input = `GuildTowerOveriewPanel
        GuildTowerEndPanel
        GuildTowerRankPanel
        GuildTowerRewardPanel
        GuildTowerPinInfoRolePanel
        GuildTowerPinInfoGuildPanel
        GuildTowerRightDescVie`;
        const prefabs = await fg(input.split(/\s+/).map(v => `**/${v}.prefab`), { cwd: toolchain.opts.projectRoot });
        console.log('prefabs count: ' + prefabs.length);
        await this.takeOffLegacyImagesOfPrefabs(prefabs.map(v => path.join(toolchain.opts.projectRoot, v)));
        prefabs.forEach(v => fs.copyFileSync(path.join(toolchain.opts.projectRoot, v), path.join('D:/works/dp_cn/trunk', v)))
    }

    /**将旧图替换成色块 */
    public async takeOffLegacyImages(): Promise<void> {
        if (!toolchain.opts.input) {
            throw 'use -i to specify the base date';
        }
        const baseDate = moment(toolchain.opts.input);

        const svn = new SVN();
        svn.loadCache();

        const resolutions: IResolution[] = [];
        const imgRoot = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources/ui');
        const imgs = await fg(['**/*.png', '**/*.jpg'], { cwd: imgRoot, ignore: ['font/**/@*/*.*', 'channel/**/*.*', 'icon/**/*.*', 'map/**/*.*', 'platIcon/**/*.*'] });
        for (const img of imgs) {
            const file = path.join(imgRoot, img);
            try {
                const date = await svn.getLastChangedDate(file);
                if (date != null) {
                    if (moment(date).diff(baseDate, 'd') < 0) {
                        const guid = await UnityHelper.readGUID(file + '.meta');
                        resolutions.push({ file, guid, color: null });
                    }
                } else {
                    console.log('could not fetch last changed date for: ' + file);
                }
            } catch(e) {
                console.error('some error occurs with ' + file + ': ' + (e instanceof Error ? e.message + '\n' + e.stack : e));
                const guid = await UnityHelper.readGUID(file + '.meta');
                resolutions.push({ file, guid, color: null });
            }
        }

        await svn.save();

        if (resolutions.length == 0) {
            console.log('no images to be replaced');
            return;
        }

        const uiRoot = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources/ui');
        const targets = await fg('**/*.prefab', { cwd: uiRoot });
        const prefabs = targets.map(v => path.join(uiRoot, v));
        await this.replaceWithDominantColor(resolutions, prefabs);
    }

    public async takeOffLegacyImagesOfPrefabs(prefabs: string[]): Promise<void> {
        const assetsRoot = path.join(toolchain.opts.projectRoot, 'Assets');
        const imgs = await fg(['**/*.png', '**/*.jpg', '**/*.tga'], { cwd: assetsRoot });
        const resolutions: IResolution[] = [];
        for (const img of imgs) {
            const file = path.join(assetsRoot, img);
            const guid = await UnityHelper.readGUID(file + '.meta');
            resolutions.push({ file, guid, color: null });
        }

        await this.replaceWithDominantColor(resolutions, prefabs);
    }

    private async replaceWithDominantColor(resolutions: IResolution[], prefabs: string[]): Promise<void> {
        console.log('replaceWithDominantColor...');

        for (const prefab of prefabs) {
            console.log('process: ' + prefab);
            const prefabContent = await fs.readFile(prefab, 'utf-8');
            const lines = prefabContent.split(/\r?\n/);

            let prevColorLine = -1, replacedCnt = 0, skip = false;;
            for (let i = 0, len = lines.length; i < len; i++) {
                const line = lines[i];
                if (line.startsWith('  m_Color: ')) {
                    prevColorLine = i;
                    continue;
                }
                if (line.startsWith('  m_Texture: ') || line.startsWith('  m_Sprite: ')) {
                    for (const rsl of resolutions) {
                        if (line.includes(rsl.guid)) {
                            if (rsl.color == null) {
                                const { data, info } = await sharp(rsl.file).raw().toBuffer({ resolveWithObject: true });
                                const imageData = { data, width: info.width, height: info.height };
                                const colors = getDominantColors(imageData, 1);
                                rsl.color = colors.rgb[0];
                            }
                            lines[i] = line.startsWith('  m_Texture: ') ? '  m_Texture: {fileID: 0}' : '  m_Sprite: {fileID: 0}';
                            if (prevColorLine > 0) {
                                lines[prevColorLine] = lines[prevColorLine].replace(/(?<=\br\b: )[^,]+/, (rsl.color[0] / 255).toFixed(8)).
                                replace(/(?<=\bg\b: )[^,]+/, (rsl.color[1] / 255).toFixed(8)).
                                replace(/(?<=\bb\b: )[^,]+/, (rsl.color[2] / 255).toFixed(8))
                            } else {
                                console.error('texture color line not found for guid: ' + rsl.guid + ', in prefab: ' + prefab);
                                skip = true;
                            }
                            replacedCnt++;
                            break;
                        }
                    }
                    if (skip) continue;
                }
            }
            if (replacedCnt > 0) {
                await fs.writeFile(prefab, lines.join('\n'), 'utf-8');
                console.log(`${replacedCnt} texure replaced: ${prefab}`);
            }
        }
    }
}